<script lang="ts">
    import { onMount } from "svelte";
    import Icon from "../Common/Icons/Icon.svelte";
    import { useClassList } from "../utils/useClassList";
    import { useStyle } from "../utils/useStyle";
    import { useTransition } from "../utils/useTransition";
    import type { DrawerProps } from "./Drawer";
    import usePortal from "../utils/usePortal";

    let { visible = $bindable(false), ...props }: DrawerProps = $props();
    let destroyed = $state(props.destroyOnClose && !visible);
    const align = $derived(props.align ?? "right");
    const transfer = props.transfer ?? true;
    const maskCloseable = props.maskCloseable ?? true;
    const size = $derived((props.size ?? 256) + "px");
    const style = $derived(useStyle({}, { [align === "left" || align === "right" ? "width" : "height"]: size }));
    const classList = $derived(
        useClassList(props, "cm-drawer", {
            [`cm-drawer-${align}`]: align,
            "cm-drawer-inline": !transfer,
        })
    );
    let box: any;
    let target: any;
    let originBodyOverflow: string;

    const transition = useTransition({
        el: () => box,
        target: () => target,
        startClass: "cm-drawer-visible",
        activeClass: "cm-drawer-open",
        onLeave: () => {
            props.onclose && props.onclose();
            document.body.style.overflow = originBodyOverflow;
            if (props.destroyOnClose) {
                destroyed = true;
            }
        },
        onEnter: () => {
            originBodyOverflow = document.body.style.overflow;
            document.body.style.overflow = "hidden";
        },
    });

    const onMaskClick = () => {
        if (maskCloseable) {
            onClose();
        }
    };

    const onClose = () => {
        visible = false;
    };

    $effect(() => {
        const v = visible;
        if (v) {
            if (props.destroyOnClose) {
                destroyed = false;
            }
            transition.enter();
            props.onshow?.();
        } else {
            transition.leave();
        }
    });

    const onKeyUp = (e: KeyboardEvent) => {
        if (props.escClose && e.code === "Escape") {
            visible = false;
        }
    };

    onMount(() => {
        if (!transfer) {
            const parentStyle = box?.parentElement.style;
            if (parentStyle) {
                parentStyle.setProperty("position", "relative");
                parentStyle.setProperty("overflow", "hidden");
            }
        }
    });

    const id = "cm-drawer-portal";
</script>

{#snippet render()}
    <!-- svelte-ignore a11y_no_static_element_interactions -->
    <div class={classList} style={props.style} bind:this={box} tabIndex={0} onkeyup={onKeyUp}>
        <!-- svelte-ignore a11y_click_events_have_key_events -->
        <div class="cm-drawer-mask" onclick={onMaskClick}></div>
        <div class="cm-drawer-wrap" {style} bind:this={target}>
            {#if props.title}
                <div class="cm-drawer-title">
                    {#if typeof props.title === "function"}
                        {@render props.title()}
                    {:else}
                        {props.title}
                    {/if}
                </div>
            {/if}
            {#if props.hasClose ?? true}
                <!-- svelte-ignore a11y_click_events_have_key_events -->
                <span class="cm-drawer-close" onclick={onClose}>
                    {#if props.closeIcon}
                        {@render props.closeIcon()}
                    {:else}
                        <Icon icon="times" />
                    {/if}
                </span>
            {/if}
            <div class="cm-drawer-body">
                {#if !destroyed}
                    {@render props.children?.()}
                {/if}
            </div>
            {#if props.footer}
                <div class="cm-drawer-footer">
                    {#if typeof props.footer === "function"}
                        {@render props.footer()}
                    {:else}
                        {props.footer}
                    {/if}
                </div>
            {/if}
        </div>
    </div>
{/snippet}

{#if transfer}
    <Portal target={usePortal(id, id)}>
        {@render render()}
    </Portal>
{:else}
    {@render render()}
{/if}
